#include "discovery_client_impl.h"
#include "discovery_client.h"
#include "utils_log.h"
#include <stdexcept>
#include <cstring>
#include <new>
#include <memory>
#include <uv.h>
#include <iostream>
#include "protocol.h"

namespace El {
namespace Discovery {

const char *DiscoveryClientImpl::MULTICAST_ADDR = "239.1.2.3";
const int DiscoveryClientImpl::PORT = 53702;

IDiscoveryClient &IDiscoveryClient::GetInstance()
{
    static DiscoveryClientImpl instance;
    return instance;
}

DiscoveryClientImpl::DiscoveryClientImpl()
{
    loop_ = new (std::nothrow) uv_loop_t;
    if (!loop_) {
        EL_ERROR("Failed to allocate uv_loop_t");
        throw std::runtime_error("Failed to allocate uv_loop_t");
    }
    int r = uv_loop_init(loop_);
    if (r != 0) {
        EL_ERROR("Failed to initialize uv loop: {}", uv_strerror(r));
        delete loop_;
        loop_ = nullptr;
        throw std::runtime_error("Failed to initialize uv loop");
    }
    loop_->data = this; // Store 'this' pointer for callbacks

    // 初始化Protocol实例
    protocol_ = Protocol::IProtocol::GetCustomInstance("discovery");
}

DiscoveryClientImpl::~DiscoveryClientImpl()
{
    Stop(); // Ensure resources are released
    if (loop_) {
        // Ensure all handles are closed before closing the loop
        int r = uv_loop_close(loop_);
        if (r == UV_EBUSY) {
            EL_WARN("Loop has active handles/requests, attempting walk and close again.");
            uv_walk(loop_, WalkCallback, nullptr);
            // Run the loop once more to process close callbacks
            uv_run(loop_, UV_RUN_NOWAIT);
            r = uv_loop_close(loop_); // Try closing again
        }
        if (r != 0) {
            EL_ERROR("Failed to close uv loop: {}", uv_strerror(r));
        }
        delete loop_;
        loop_ = nullptr;
    }
}

bool DiscoveryClientImpl::Start(int32_t timeout)
{
    if (running_.load()) {
        EL_WARN("Discovery client already running.");
        return true;
    }

    if (!loop_) {
        EL_ERROR("Cannot start, uv loop is not initialized.");
        return false;
    }

    // 保存超时设置
    timeoutSeconds_ = timeout;

    // Initialize UDP send address
    uv_ip4_addr(MULTICAST_ADDR, PORT, &sendAddr_);

    // Initialize UDP handle
    int r = uv_udp_init(loop_, &udpHandle_);
    if (r != 0) {
        EL_ERROR("Failed to initialize UDP handle: {}", uv_strerror(r));
        return false;
    }
    udpHandle_.data = this; // Store 'this' for callbacks

    struct sockaddr_in recv_addr;
    // 绑定到任意端口以接收响应
    uv_ip4_addr("0.0.0.0", 0, &recv_addr);

    // Bind UDP handle
    r = uv_udp_bind(&udpHandle_, (const struct sockaddr *)&recv_addr, UV_UDP_REUSEADDR);
    if (r != 0) {
        EL_ERROR("Failed to bind UDP handle: {}", uv_strerror(r));
        uv_close((uv_handle_t *)&udpHandle_, nullptr);
        return false;
    }

    // Start receiving UDP messages
    r = uv_udp_recv_start(&udpHandle_, OnAllocBuffer, OnUdpRecv);
    if (r != 0) {
        EL_ERROR("Failed to start UDP receive: {}", uv_strerror(r));
        uv_close((uv_handle_t *)&udpHandle_, nullptr);
        return false;
    }

    running_.store(true);

    // Start the libuv loop in a separate thread
    loopThread_ = std::thread(&DiscoveryClientImpl::RunLoop, this);

    // 直接发送discovery请求，不使用定时器
    SendDiscoveryRequest();

    EL_INFO("Discovery client started, will timeout in {} seconds", timeoutSeconds_);
    return true;
}

void DiscoveryClientImpl::Stop()
{
    if (!running_.load()) {
        return;
    }

    running_.store(false); // Signal the loop to stop

    if (loop_) {
        // Use uv_async_send to wake up the loop if it's blocked
        uv_async_t *async = new uv_async_t; // Allocate on heap
        uv_async_init(loop_, async, [](uv_async_t *handle) {
            // This callback runs in the loop thread
            uv_close((uv_handle_t *)handle,
                     [](uv_handle_t *h) { delete (uv_async_t *)h; }); // Close and delete async handle
        });
        uv_async_send(async); // Wake up the loop
    }

    // Join the loop thread
    if (loopThread_.joinable()) {
        loopThread_.join();
    }

    EL_INFO("Discovery client stopped.");
}

int32_t DiscoveryClientImpl::Register(const Proc &proc)
{
    if (!proc) {
        EL_ERROR("Cannot register null callback");
        return -1;
    }

    int32_t handle = callbacks_.Register(proc);
    EL_DEBUG("Registered callback with handle {}", handle);
    return handle;
}

void DiscoveryClientImpl::Unregister(int32_t handle)
{
    callbacks_.Unregister(handle);
}

// --- Private Helper Methods ---

void DiscoveryClientImpl::RunLoop()
{
    EL_DEBUG("Libuv loop thread started.");

    // 计算超时时间
    auto start_time = std::chrono::steady_clock::now();

    while (running_.load()) {
        int r = uv_run(loop_, UV_RUN_ONCE);
        if (r == 0 && !running_.load()) {
            // No more active handles or requests, and we are stopping
            break;
        }

        // 检查超时
        auto current_time = std::chrono::steady_clock::now();
        auto elapsed = std::chrono::duration_cast<std::chrono::seconds>(current_time - start_time).count();
        if (elapsed >= timeoutSeconds_) {
            EL_INFO("Discovery timeout after {} seconds", timeoutSeconds_);
            running_.store(false);
            break;
        }
    }

    EL_DEBUG("Libuv loop stopping...");
    // Stop and close handles before exiting the thread
    StopLoopHandles();
    // Run the loop one last time to process close callbacks
    uv_run(loop_, UV_RUN_NOWAIT);
    EL_DEBUG("Libuv loop thread finished.");
}

void DiscoveryClientImpl::StopLoopHandles()
{
    if (!loop_)
        return;

    // Stop receiving and close UDP handle
    if (uv_is_active((uv_handle_t *)&udpHandle_)) {
        int r = uv_udp_recv_stop(&udpHandle_);
        if (r != 0) {
            EL_ERROR("Failed to stop UDP recv: {}", uv_strerror(r));
        }
        // Close handle, ensuring callback runs in the loop
        uv_close((uv_handle_t *)&udpHandle_, nullptr);
    }
}

void DiscoveryClientImpl::SendDiscoveryRequest()
{
    if (!protocol_) {
        EL_ERROR("Protocol instance not initialized");
        return;
    }

    // 创建发现请求
    std::string id = "discovery-" + std::to_string(std::chrono::steady_clock::now().time_since_epoch().count());
    std::string method = "discovery.search";
    nlohmann::json params = {{"client_id", "discovery_client"}, {"filters", nlohmann::json::object()}};

    std::string request_body = protocol_->CreateRequest(id, method, params);

    // 构造HTTP请求
    std::string request_str = BuildHttpRequest("POST", request_body);

    // 发送UDP多播消息
    uv_buf_t send_buf = uv_buf_init((char *)request_str.c_str(), request_str.length());
    uv_udp_send_t *send_req = new (std::nothrow) uv_udp_send_t;
    if (!send_req) {
        EL_ERROR("Failed to allocate uv_udp_send_t");
        return;
    }

    int r = uv_udp_send(send_req, &udpHandle_, &send_buf, 1, (const struct sockaddr *)&sendAddr_, OnUdpSend);
    if (r != 0) {
        EL_ERROR("Failed to send discovery request: {}", uv_strerror(r));
        delete send_req;
    } else {
        EL_DEBUG("Discovery request sent to {}:{}", MULTICAST_ADDR, PORT);
    }
}

// HTTP helpers
bool DiscoveryClientImpl::ParseHttpMessage(const std::string &raw_data, std::string &headers, std::string &body)
{
    // 寻找HTTP头部和消息体的分隔符（双回车换行）
    size_t header_end = raw_data.find("\r\n\r\n");

    if (header_end != std::string::npos) {
        // 找到HTTP头部
        headers = raw_data.substr(0, header_end);
        body = raw_data.substr(header_end + 4); // +4 跳过 \r\n\r\n
        EL_DEBUG("HTTP headers: {}", headers);
        EL_DEBUG("HTTP body: {}", body);
        return true;
    } else {
        // 没有找到HTTP头部，可能是纯消息体
        EL_WARN("No HTTP headers found, treating as raw message body");
        headers = "";
        body = raw_data;
        return false;
    }
}

std::string DiscoveryClientImpl::BuildHttpRequest(const std::string &method, const std::string &body)
{
    // 构造简单的HTTP请求
    std::string request = method +
                          " /discovery HTTP/1.1\r\n"
                          "Host: " +
                          std::string(MULTICAST_ADDR) + ":" + std::to_string(PORT) +
                          "\r\n"
                          "Content-Type: application/json\r\n"
                          "Content-Length: " +
                          std::to_string(body.size()) +
                          "\r\n"
                          "Connection: close\r\n"
                          "\r\n" +
                          body;

    return request;
}

// --- Static libuv Callbacks ---

void DiscoveryClientImpl::OnAllocBuffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf)
{
    (void)handle; // Mark as unused

    // 根据建议大小或使用合理的默认值
    size_t buffer_size = suggested_size > 0 ? suggested_size : 65536;

    // 动态分配内存，将在OnUdpRecv中释放
    char *buffer = new (std::nothrow) char[buffer_size];
    if (!buffer) {
        // 内存分配失败，提供一个小的备用缓冲区
        static char emergency_buffer[1];
        buf->base = emergency_buffer;
        buf->len = 0; // 实际上不接收数据
        EL_ERROR("Memory allocation failed in OnAllocBuffer");
        return;
    }

    buf->base = buffer;
    buf->len = buffer_size;
}

void DiscoveryClientImpl::OnUdpRecv(uv_udp_t *handle,
                                    ssize_t nread,
                                    const uv_buf_t *buf,
                                    const struct sockaddr *addr,
                                    unsigned flags)
{
    (void)flags; // Mark as unused

    // 确保在函数退出时释放缓冲区
    std::unique_ptr<char[]> buffer_guard(buf->base);

    DiscoveryClientImpl *self = static_cast<DiscoveryClientImpl *>(handle->data);
    if (self) {
        self->HandleUdpRecv(nread, buf, addr, flags);
    }
}

void DiscoveryClientImpl::OnUdpSend(uv_udp_send_t *req, int status)
{
    if (status) {
        EL_ERROR("UDP send error: {}", uv_strerror(status));
    }
    // Free the send request structure
    delete req;
}

void DiscoveryClientImpl::WalkCallback(uv_handle_t *handle, void *arg)
{
    (void)arg; // Mark as unused
    if (!uv_is_closing(handle)) {
        EL_DEBUG("Closing handle during walk: type {}", handle->type);
        uv_close(handle, nullptr); // Close any handles that weren't explicitly closed
    }
}

// --- Member Function Callbacks ---

void DiscoveryClientImpl::HandleUdpRecv(ssize_t nread, const uv_buf_t *buf, const struct sockaddr *addr, unsigned flags)
{
    (void)flags; // Mark as unused
    if (nread < 0) {
        EL_ERROR("UDP receive error: {}", uv_strerror(nread));
        return;
    }

    if (nread == 0) {
        // EAGAIN or EWOULDBLOCK, ignore
        return;
    }

    if (addr == nullptr) {
        // Datagram truncated or no sender info
        EL_WARN("Received UDP packet with no sender address or truncated.");
        return;
    }

    // 获取发送者信息
    char sender_ip[17] = {0};
    uv_ip4_name((const struct sockaddr_in *)addr, sender_ip, 16);
    int sender_port = ntohs(((const struct sockaddr_in *)addr)->sin_port);

    // 解析收到的原始数据
    std::string raw_data(buf->base, nread);
    EL_DEBUG("Received %zd bytes from {}:{}", nread, sender_ip, sender_port);
    EL_DEBUG("Data: {}", raw_data.c_str());

    // 解析HTTP消息
    std::string headers;
    std::string body;
    ParseHttpMessage(raw_data, headers, body);

    // 检查是否是HTTP响应
    if (headers.find("HTTP/1.1 200") == std::string::npos) {
        EL_WARN("Received non-200 response or invalid HTTP message");
        return;
    }

    // 使用Protocol接口解析响应
    if (!protocol_) {
        EL_ERROR("Protocol instance not initialized");
        return;
    }

    // 使用 ProtocolImpl 解析请求
    std::string id;
    nlohmann::json result;
    if (!protocol_->ParseResponse(body, id, result)) {
        EL_ERROR("Failed to parse WebSocket request on connection {}: {}", body.c_str());
        return;
    }

    // 解析搜索命令返回信息
    callbacks_.InvokeAll(result);
}

} // namespace Discovery
} // namespace El
